/*******************************************************************************
 * Copyright (c) 2000, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package com.architexa.org.eclipse.gef.editpolicies;

import com.architexa.org.eclipse.draw2d.Connection;
import com.architexa.org.eclipse.draw2d.ConnectionAnchor;
import com.architexa.org.eclipse.draw2d.ConnectionLayer;
import com.architexa.org.eclipse.draw2d.ConnectionRouter;
import com.architexa.org.eclipse.draw2d.PolylineConnection;
import com.architexa.org.eclipse.draw2d.geometry.Point;
import com.architexa.org.eclipse.gef.EditPart;
import com.architexa.org.eclipse.gef.LayerConstants;
import com.architexa.org.eclipse.gef.NodeEditPart;
import com.architexa.org.eclipse.gef.Request;
import com.architexa.org.eclipse.gef.commands.Command;
import com.architexa.org.eclipse.gef.requests.CreateConnectionRequest;
import com.architexa.org.eclipse.gef.requests.DropRequest;
import com.architexa.org.eclipse.gef.requests.ReconnectRequest;



/**
 * A GraphicalNodeEditPolicy is responsible for creating and reconnecting connections
 * graphically.
 * 
 * Created on :Nov 11, 2002
 * @author hudsonr
 * @since 2.0
 */
public abstract class GraphicalNodeEditPolicy
	extends GraphicalEditPolicy
{

/**
 * the current FeedbackHelper
 */
protected FeedbackHelper feedbackHelper;
/**
 * The connection feedback displayed during creates
 */
protected Connection connectionFeedback;

/**
 * Returns a connection to be used as feeback during creates.
 * @param req the operation being performed
 * @return a connection to use as feedback
 */
protected Connection createDummyConnection(Request req) {
	return new PolylineConnection();
}

/**
 * @see com.architexa.org.eclipse.gef.EditPolicy#deactivate()
 */
public void deactivate() {
	if (connectionFeedback != null) {
		removeFeedback(connectionFeedback);
		feedbackHelper = null;
		connectionFeedback = null;
	}
	super.deactivate();
}

/**
 * Erases connection feedback if necessary. Frees unused fields.
 * @param request the CreateConnectionRequest
 */
protected void eraseCreationFeedback(CreateConnectionRequest request) {
	if (connectionFeedback != null) {
		removeFeedback(connectionFeedback);
		feedbackHelper = null;
		connectionFeedback = null;
	}
}

/**
 * Calls {@link #eraseCreationFeedback(CreateConnectionRequest)} when appropriate.
 * @see com.architexa.org.eclipse.gef.EditPolicy#eraseSourceFeedback(Request)
 */
public void eraseSourceFeedback(Request request) {
	if (REQ_CONNECTION_END.equals(request.getType()))
		eraseCreationFeedback((CreateConnectionRequest)request);
}

/**
 * Override to erase target feedback. Does nothing by default.
 * @param request the DropRequest
 */
protected void eraseTargetConnectionFeedback(DropRequest request) { }

/**
 * Calls {@link #eraseTargetConnectionFeedback(DropRequest)} when appropriate.
 * @see com.architexa.org.eclipse.gef.EditPolicy#eraseTargetFeedback(Request)
 */
public void eraseTargetFeedback(Request request) {
	if (REQ_CONNECTION_START.equals(request.getType())
	  || REQ_CONNECTION_END.equals(request.getType())
	  || REQ_RECONNECT_SOURCE.equals(request.getType())
	  || REQ_RECONNECT_TARGET.equals(request.getType()))
		eraseTargetConnectionFeedback((DropRequest) request);
}

/**
 * Factors the request into one of four abstract methods. Subclasses must implement these
 * methods.
 * @see com.architexa.org.eclipse.gef.EditPolicy#getCommand(Request)
 */
public Command getCommand(Request request) {
	if (REQ_CONNECTION_START.equals(request.getType()))
		return getConnectionCreateCommand((CreateConnectionRequest)request);
	if (REQ_CONNECTION_END.equals(request.getType()))
		return getConnectionCompleteCommand((CreateConnectionRequest)request);
	if (REQ_RECONNECT_TARGET.equals(request.getType()))
		return getReconnectTargetCommand((ReconnectRequest)request);
	if (REQ_RECONNECT_SOURCE.equals(request.getType()))
		return getReconnectSourceCommand((ReconnectRequest)request);

	return null;
}

/**
 * Returns the Command that will create the connection. This is second part of creation.
 * {@link CreateConnectionRequest#getStartCommand()} is used here to obtain the
 * contribution from the EditPart from which the User started the <i>creation</i>.
 * @param request the CreateConnectionRequest
 * @return the complete command to create a connection
 */
protected abstract Command getConnectionCompleteCommand(CreateConnectionRequest request);

/**
 * Returns the Command that represents the first half of creating a connection. This
 * Command will be passed to the target node EditPart. The target node may do anything
 * necessary to create a Command that represents the entire creation.
 * @param request the CreateConnectionRequest
 * @see #getConnectionCompleteCommand(CreateConnectionRequest)
 * @return a Command representing half of a connection creation
 */
protected abstract Command getConnectionCreateCommand(CreateConnectionRequest request);

/**
 * Returns the ConnectionRouter for the creation feedback's connection.
 * @param request the create request
 * @return a connection router
 * @since 3.2
 */
protected ConnectionRouter getDummyConnectionRouter(CreateConnectionRequest request) {
	return ((ConnectionLayer) getLayer(LayerConstants.CONNECTION_LAYER))
			.getConnectionRouter();
}

/**
 * Returns the FeedbackHelper that is ready to use. The feedback helper must be configured
 * with the connection that will be used to display feedback, and that connection must be
 * added to the appropriate layer in the diagram.
 * @param request the CreateConnectionRequest
 * @return a FeedbackHelper
 */
protected FeedbackHelper getFeedbackHelper(CreateConnectionRequest request) {
	if (feedbackHelper == null) {
		feedbackHelper = new FeedbackHelper();
		Point p = request.getLocation();
		connectionFeedback = createDummyConnection(request);
		connectionFeedback.setConnectionRouter(getDummyConnectionRouter(request));
		connectionFeedback.setSourceAnchor(getSourceConnectionAnchor(request));
		feedbackHelper.setConnection(connectionFeedback);
		addFeedback(connectionFeedback);
		feedbackHelper.update(null, p);
	}
	return feedbackHelper;
}

/**
 * Returns the <code>Command</code> to reconnect a connection's <i>target</i> end to the
 * host.
 * @param request the ReconnectRequest
 * @return a Command
 */
protected abstract Command getReconnectTargetCommand(ReconnectRequest request);

/**
 * Returns the <code>Command</code> to reconnect a connection's <i>source</i> end to the
 * host.
 * @param request the ReconnectRequest
 * @return a Command
 */
protected abstract Command getReconnectSourceCommand(ReconnectRequest request);

/**
 * Called during the display of creation feedback to snap the feedback to the nearest
 * source ConnectionAnchor.
 * @param request CreateConnectionRequest
 * @return <code>null</code> or the nearest source ConnectionAnchor
 */
protected ConnectionAnchor getSourceConnectionAnchor(CreateConnectionRequest request) {
	EditPart source = request.getSourceEditPart();
	return source instanceof NodeEditPart 
		? ((NodeEditPart) source).getSourceConnectionAnchor(request)
		: null;
}

/**
 * Called during the display of creation feedback to snap the feedback to the nearest
 * target ConnectionAnchor.
 * @param request CreateConnectionRequest
 * @return <code>null</code> or the nearest target ConnectionAnchor
 */
protected ConnectionAnchor getTargetConnectionAnchor(CreateConnectionRequest request) {
	EditPart target = request.getTargetEditPart();
	return target instanceof NodeEditPart 
		? ((NodeEditPart) target).getTargetConnectionAnchor(request)
		: null;
}

/**
 * Returns the <i>host</i> for the appropriate <code>Requests</code>. Returns
 * <code>null</code> otherwise.
 * @see com.architexa.org.eclipse.gef.EditPolicy#getTargetEditPart(Request)
 */
public EditPart getTargetEditPart(Request request) {
	if (REQ_CONNECTION_START.equals(request.getType())
		|| REQ_CONNECTION_END.equals(request.getType())
		|| REQ_RECONNECT_SOURCE.equals(request.getType())
		|| REQ_RECONNECT_TARGET.equals(request.getType()))
		return getHost();
	return null;
}

/**
 * Shows feedback during a creation.
 * @param request CreateConnectionRequest
 */
protected void showCreationFeedback(CreateConnectionRequest request) {
	FeedbackHelper helper = getFeedbackHelper(request);
	Point p = new Point(request.getLocation());
	helper.update(getTargetConnectionAnchor(request), p);
}

/**
 * calls {@link #showCreationFeedback(CreateConnectionRequest)} when appropriate.
 * @see com.architexa.org.eclipse.gef.EditPolicy#showSourceFeedback(Request)
 */
public void showSourceFeedback(Request request) {
	if (REQ_CONNECTION_END.equals(request.getType()))
		showCreationFeedback((CreateConnectionRequest)request);
}

/**
 * Override to show target connection feedback. Does nothing by default.
 * @param request the DropRequest
 */
protected void showTargetConnectionFeedback(DropRequest request) { }

/**
 * Calls {@link #showTargetConnectionFeedback(DropRequest)} when appropriate.
 * @see com.architexa.org.eclipse.gef.EditPolicy#showTargetFeedback(Request)
 */
public void showTargetFeedback(Request request) {
	if (REQ_CONNECTION_START.equals(request.getType())
			|| REQ_CONNECTION_END.equals(request.getType())
			|| REQ_RECONNECT_SOURCE.equals(request.getType())
			|| REQ_RECONNECT_TARGET.equals(request.getType()))
		showTargetConnectionFeedback((DropRequest) request);
}

}
